package cn.agiledata.bank.netReturn.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import cn.agiledata.bank.audit.exception.AuditException;
import cn.agiledata.bank.common.dao.AccountTemplate;
import cn.agiledata.bank.common.dao.AccountTemplateInter;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.ForeDict;
import cn.agiledata.bank.common.util.MD5;
import cn.agiledata.bank.common.util.UniqueIdentityUtil;
import cn.agiledata.bank.common.util.WeatherUtil;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.EsPrePayTrans;
import cn.agiledata.bank.hibernateBean.Operator;
import cn.agiledata.bank.hibernateBean.SubAccount;
import cn.agiledata.bank.hibernateBean.Transaction;
import cn.agiledata.bank.netReturn.exception.NetReturnException;
import cn.agiledata.bank.netReturn.form.NetReturnForm;
import cn.agiledata.bank.netReturn.logic.NetReturnBean;
import cn.agiledata.bank.netReturn.logic.NetReturnResponse;
import cn.agiledata.bank.transaction.audit.service.EsPrePayTransService;
import cn.agiledata.bank.transaction.dao.ActionTypeDao;
import cn.agiledata.bank.transaction.dao.TransactionDao;
import cn.agiledata.bank.transaction.exception.TransactionException;
import com.vnv.infrastructure.logic.IPBAppFactory;

public class NetReturnServiceImpl implements NetReturnService {

	private TransactionDao transactionDao;

	private AccountTemplate accountTemplate;

	private ActionTypeDao actionTypeDao;

	public AccountTemplate getAccountTemplate() {
		return accountTemplate;
	}

	public void setAccountTemplate(AccountTemplate accountTemplate) {
		this.accountTemplate = accountTemplate;
	}

	public ActionTypeDao getActionTypeDao() {
		return actionTypeDao;
	}

	public void setActionTypeDao(ActionTypeDao actionTypeDao) {
		this.actionTypeDao = actionTypeDao;
	}

	public TransactionDao getTransactionDao() {
		return transactionDao;
	}

	public void setTransactionDao(TransactionDao transactionDao) {
		this.transactionDao = transactionDao;
	}

	public void validateMac(Map parameters, String mac) throws NetReturnException {
		if (mac != null) {
			String accountId = (String) parameters.get("merchantId");
			String merchantKey = getAccountKey(accountId);
			if (merchantKey == null)
				merchantKey = "";
			parameters.put("merchantKey", merchantKey);
			String[] keys = { "merchantId", "merchantUrl", "orderNo", "amount", "merchantKey" };
			if (!mac.equalsIgnoreCase(getMac(keys, parameters))) {
				throw new NetReturnException("Mac校验失败");
			}
		}
	}

	public String getAccountKey(String accountId) {
		Account account = this.accountTemplate.getAccountByAccountId(accountId);
		return account == null ? null : account.getKey();
	}

	private String getMac(String[] keys, Map parameters) {
		return new MD5().getMD5ofStr(linkParameters(keys, parameters));
	}

	private String linkParameters(String[] keys, Map parameters) {
		String s = "";
		s += keys[0] + "=" + parameters.get(keys[0]);
		for (int i = 1; i < keys.length; i++) {
			Object value = parameters.get(keys[i]);
			if (value != null)
				s += "&" + keys[i] + "=" + value;
		}
		return s;
	}

	public List getNetReturnList(NetReturnForm form) throws NetReturnException {
		List netReturnList = new ArrayList();
		String[] orderIds = form.getOrderNo().split(",");
		String[] amounts = form.getAmount().split(",");
		if (form.getBatchModel().equals("0") 
				&& orderIds.length != 1
				&& amounts.length != 1) {
			throw new NetReturnException("您选择的是单笔退款,输入了多笔退款!");
		}
		if (orderIds.length == 0 || amounts.length == 0) {
			throw new NetReturnException("无退账数据!");

		}
		if (orderIds.length != amounts.length) {
			throw new NetReturnException("订单id与amount数量不一致");

		}
		//过滤重复的记录
		boolean flag = false;
		String orderId = "";
		for (int i = 0; i < orderIds.length; i++) {
			for (int j = i + 1; j < orderIds.length; j++) {
				if (orderIds[i].equals(orderIds[j])) {
					flag = true;
					orderId = orderIds[i];
					break;
				}
			}
		}
		if (flag)
			throw new NetReturnException("退款申请存在重复的记录:" + orderId);
		//封装退款记录,并过滤金额错误记录
		for (int i = 0; i < orderIds.length; i++) {
			try {
				NetReturnBean netReturnBean = new NetReturnBean(orderIds[i], new BigDecimal(amounts[i]));
				netReturnList.add(netReturnBean);
			} catch (Exception ex) {
				throw new NetReturnException("数据格式错误");
			}
		}
		return netReturnList;
	}

	public Map validateNetReturn(List netReturnList, String accountId) throws NetReturnException {
		Account account = accountTemplate.getAccountByAccountId(accountId);
		List result = transactionDao.getValReturnMoney(account, netReturnList);
		Map transMap = new HashMap();
		if (result == null || result.size() == 0) {
			transMap.put("notExsitTrans", netReturnList);
			return transMap;
		} else {
			// 过滤:order id与 trans id实为一条交易,但做为两条记录申请
			for (Iterator iter = result.iterator(); iter.hasNext();) {
				Transaction trans = (Transaction) iter.next();
				int flag = 0;
				for (Iterator it = netReturnList.iterator(); it.hasNext();) {
					NetReturnBean netReturnBean = (NetReturnBean) it.next();
					if (netReturnBean.getOrderId().equals(trans.getTransId()) || netReturnBean.getOrderId().equals(trans.getOrderId())) {
						flag++;
					}
				}
				if (flag > 1)
					throw new NetReturnException("退款申请存在重复的记录:" + trans.getTransId() + "," + trans.getOrderId());
			}
			List legalTrans = new ArrayList();
			List illegalTrans = new ArrayList();
			// 过滤不符合退款条件的退款申请
			for (Iterator iter = netReturnList.iterator(); iter.hasNext();) {
				NetReturnBean netReturnBean = (NetReturnBean) iter.next();
				for (Iterator it = result.iterator(); it.hasNext();) {
					Transaction trans = (Transaction) it.next();
					if (netReturnBean.getOrderId().equals(trans.getTransId()) || netReturnBean.getOrderId().equals(trans.getOrderId())) {
						legalTrans.add(netReturnBean);
						iter.remove();
					}
				}
				netReturnBean = null;
			}
			if (netReturnList.size() > 0) {
				transMap.put("notExsitTrans", netReturnList);
			}
			// 过滤符合退款条件但是退款金额大于交易金额的退款申请
			if (legalTrans.size() > 0) {
				for (Iterator it = result.iterator(); it.hasNext();) {
					Transaction trans = (Transaction) it.next();
					for (Iterator iter = legalTrans.iterator(); iter.hasNext();) {
						NetReturnBean netReturnBean = (NetReturnBean) iter.next();
						if ((netReturnBean.getOrderId().equals(trans.getTransId()) || netReturnBean.getOrderId().equals(trans.getOrderId()))
								&& netReturnBean.getAmount().compareTo(new BigDecimal(trans.getAmount().toString())) ==1) {
							illegalTrans.add(netReturnBean);
						}
					}
				}
			}
			if (illegalTrans.size() > 0) {
				transMap.put("illegalTrans", illegalTrans);
			}
			return transMap;
		}
	}

	// 直接生成退款交易
	public String createReturnApply(List netReturnList, String merchantId, Operator operator, String bathModel) throws TransactionException, AuditException, Exception {
		Account account = accountTemplate.getAccountByAccountId(merchantId);
		List listTrans = transactionDao.getValReturnMoney(account, netReturnList);

		Double dbTotalAmount = new Double(0);

		// 检查退款交易
		Map mapAmounts = new HashMap();
		for (Iterator iter = netReturnList.iterator(); iter.hasNext();) {
			NetReturnBean netReturnBean = (NetReturnBean) iter.next();
			// 检查退款额
			dbTotalAmount = new Double(dbTotalAmount.doubleValue() + netReturnBean.getAmount().doubleValue());
			mapAmounts.put(netReturnBean.getOrderId(), Double.valueOf(netReturnBean.getAmount().toString()));
		}

		// 检查余额是否足够
		// 取得默认子账户
		SubAccount defaultSubAccount = account.getDefaultSubAccount();
		AccountTemplateInter ati = (AccountTemplateInter) IPBAppFactory.getObj(ForeDict.ACCOUNT_TEMPLATE);
		if (ati.compareAccountMoney(defaultSubAccount.getId().toString(), dbTotalAmount) != 0) {
			throw new NetReturnException("余额不足,请登录系统并账户充值后再进行此操作!");// 余额不足
		}

		EsPrePayTransService preService = (EsPrePayTransService) IPBAppFactory.getObj(ForeDict.SERVICE_ES_PRE_PAY_TRANS);
		String returnStr = "";
		// 检查完毕，创建退款交易
		//区别单笔跟批量
		String batchNoForRetrun = "";
		String batchNoForInner = "";
		if (bathModel.equals("1")) {
			batchNoForRetrun = UniqueIdentityUtil.getTransactionBatchNoSequence();
			batchNoForInner = UniqueIdentityUtil.getTransactionBatchNoSequence();
		}
		
		for (Iterator iter = listTrans.iterator(); iter.hasNext();) {
			Transaction trans = (Transaction) iter.next();

			EsPrePayTrans preReturnTrans = new EsPrePayTrans();
			//生成交易编号
			returnStr = UniqueIdentityUtil.getTransactionSequence();
			preReturnTrans.setTransId(returnStr);
			//区别单笔和批量
			if (bathModel.equals("1")){
				if (trans.getActionType().getId().toString().equals(Constant.ACTION_TYPE_C)) {
					preReturnTrans.setBatchNo(batchNoForInner);
					returnStr = batchNoForInner;
				} else {
					preReturnTrans.setBatchNo(batchNoForRetrun);
					returnStr = batchNoForRetrun;
				}
			}

			
			preReturnTrans.setDebit(defaultSubAccount);
			// 退款银行
			preReturnTrans.setBankSeq(trans.getBankSeq());
			// 交易类型
			if (trans.getActionType().getId().toString().equals(Constant.ACTION_TYPE_C)) {
				// 原交易为账户间交易，退款交易类型亦为账户间交易
				// 退款内部账户
				preReturnTrans.setCredit(trans.getDebit());
				preReturnTrans.setActionType(this.actionTypeDao
						.getActionType(Long.parseLong(Constant.ACTION_TYPE_C)));
			} else {
				// 其他交易类型为退款交易
				Account returnAccount = accountTemplate.getAccount(Constant.INITIAL_ACCOUNT_RETURN);
				preReturnTrans.setCredit(returnAccount.getDefaultSubAccount());
				preReturnTrans.setActionType(this.actionTypeDao
						.getActionType(Long.parseLong(Constant.ACTION_TYPE_R)));
			}
			// 交易状态为成功
			preReturnTrans.setTransStatus(Constant.ES_TRANS_STATUS_UNPAY);
			
			// 相关交易ID
			preReturnTrans.setRelating(trans.getId());
			// 非担保交易
			preReturnTrans.setTradeType(Constant.TRADE_TYPE_NOASSURE);
			// 退款金额
			if (mapAmounts.get(trans.getOrderId()) != null)
				preReturnTrans.setAmount((Double) mapAmounts.get(trans.getOrderId()));
			else
				preReturnTrans.setAmount((Double) mapAmounts.get(trans.getTransId()));
			// 交易创建日期
			preReturnTrans.setBeginDate(new Date());
			// 相关交易编号
			String strRemark = "关联交易编号：" + trans.getTransId();
			if (trans.getOrderId() != null && trans.getOrderId().trim().length() > 0) {
				strRemark += "　关联订单编号：" + trans.getOrderId();
			}
			preReturnTrans.setRemark(strRemark);
			// 设置记账模型
			// 封装插入日期和修改日期
			WeatherUtil.fillCreateAndUpdateInfo(preReturnTrans, defaultSubAccount.getAccount().getId().toString());

			// 创建待退款审核交易
			preService.createPreReturnTrans(preReturnTrans, account, operator);
		}
		return returnStr;
	}

	public NetReturnResponse backgroundResponse(NetReturnResponse netReturnResponse) {
		StringBuffer s = new StringBuffer("merchantId=");
		s.append(netReturnResponse.getAccountId());
		s.append("&orderId=").append(netReturnResponse.getOrderId());
		s.append("&amount=").append(netReturnResponse.getAmount());
		s.append("&merchantKey=").append(getAccountKey(netReturnResponse.getAccountId()));
		netReturnResponse.setMac(new MD5().getMD5ofStr(s.toString()));
		return netReturnResponse;
	}

	// 目前临时的版本校验
	public void validateVersion(String version, Map parameters) throws NetReturnException {
		if (parameters.get("version") == null || !parameters.get("version").equals("1.0.0")) {
			throw new NetReturnException("接口版本不匹配!");
		}
	}
	
	public Map getParameters(Transaction trans) {
        Map parameters = new HashMap();
        parameters.put("merchantId", trans.getCredit().getAccount().getAccountId());
        parameters.put("responseMode", String.valueOf(Constant.RESPONSE_MODE_BACKGROUND));
        parameters.put("orderId", trans.getOrderId());
        parameters.put("currencyType", trans.getCurrency());
        Double amount = trans.getAmount();
        if (amount == null) {
            amount = new Double(0);
        }
        parameters.put("amount", amount.toString());
        parameters.put("returnCode", "0000");
        parameters.put("returnMessage", "  ");
        parameters.put("merchantKey", trans.getDebit().getAccount().getKey());
        parameters.put("unsTransId", trans.getTransId());
        String[] keys = {"merchantId", "responseMode", "orderId",
                "currencyType", "amount", "returnCode", "returnMessage",
                "merchantKey"};
        String mac = getMac(keys, parameters);
        parameters.put("mac", mac);
        return parameters;
    }

}
